Skip to main content

Overview

Email content has been moved from being hardcoded in each flow, to a central dataverse table "Email Contents". This allows customizing email content per client without the risk of overriding existing email content when deploying latest Flow changes.

Each email sending flow, has got a fixed set of actions that read the "Email Contents" table on demand and pull back the relevant Subject and Email Body based on Flow name and a custom email ID hardcoded on each flow.

"Email Contents" table

This table centrally stores all email content for a specific environment/client. Columns explained:

  • Flow Name - is the name of the flow that the email content is for.
  • Flow Email ID - is the ID of a specific email on a single flow. (e.g. so there could be multiple rows and the Email Contents table with the same Flow Name, but differing Flow Email IDs identifying each individual email)
  • Email Subject - is to store the subject of the email.
  • Email Body - is to store the email body of the email.
  • Enabled for Review - is used to by Email generating flows. If this is ON, then when an Email generating flow is started, this email will be picked up, otherwise it will be ignored.

Cloud Flows

Step 01: "Get Email Content Template" Scope

We get the email content.

  • On the "FlowEmailTemplate Filter" compose action, we specify what is the current flows name and the custom ID that we assigned to this email. (e.g. first email on the flow would have ID-1, second would be ID-2, and so on.)
{
"FlowName": "Alert Adviser with Additional Notes",
"FlowEmailID": "1"
}
  • On the "List EmailContents" action - we retrieve rows relating to this Flow and Email ID specified above.
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
<entity name="tt_emailcontent">
<attribute name="tt_emailcontentid" />
<order attribute="tt_emailsubject" descending="false" />
<filter type="and">
<condition attribute="tt_flowname" operator="eq" value="@{outputs('FlowEmailTemplate_Filter')['FlowName']}" />
<condition attribute="tt_flowemailid" operator="eq" value="@{outputs('FlowEmailTemplate_Filter')['FlowEmailID']}" />
</filter>
</entity>
</fetch>
  • On "First EmailContentsID" a compose action - we select the first item from above.
@{first(outputs('List_EmailContents')?['body/value'])?['tt_emailcontentid']}
  • On "Get EmailContents by ID" - we then get the exact Email Content row that is applicable.
@{outputs('First_EmailContentsID')}

Step 02: "Update EmailTemplate" Scope

We replace wildcards with dynamic content from the Flow.

  • On the "ReplacementMapping" compose action, we specify each Wildcard and the replacement for it.
[
{
"Wildcard": "{{contact.tt_clientcode}}",
"Replacement": "@{outputs('Get_Contact_by_ID')?['body/tt_clientcode']}"
},
{
"Wildcard": "{{contact.fullname}}",
"Replacement": "@{outputs('Get_Contact_by_ID')?['body/fullname']}"
}
]
  • We then use "Replace Wildcards in EmailSubject" custom action, to replace wildcards with dynamic content on the email Subject.
{
"Text": "@{outputs('Get_EmailContents_by_ID')?['body/tt_emailsubject']}",
"ReplacementMapping": @{outputs('ReplacementMapping')}
}
  • We then use "Replace Wildcards in EmailBody" custom action, to replace wildcards with dynamic content on the email Body.
{
"Text": "@{outputs('Get_EmailContents_by_ID')?['body/tt_emailbody']}",
"ReplacementMapping": @{outputs('ReplacementMapping')}
}

Step 03: Using prepared Email Subject and Email Body

  • Email subject can then be accessed via:
@{body('Replace_Wildcards_in_EmailSubject')?['Output']}
  • Email Body can then be accessed via
@{body('Replace_Wildcards_in_EmailBody')?['Output']}